package mt.dummy;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.HashMap;
import java.util.LinkedList;

import mt.Order;
import mt.comm.ClientSideMessage;
import mt.comm.ServerComm;
import mt.comm.ServerSideMessage;
import mt.dummy.ClientMessage;
import mt.dummy.MicroTraderServerDummy;
import mt.dummy.ServerMessage;

/**
 * ServerCommDummy is used by the server to communicate with the clients.
 * 
 * @author Pedro,Rita, Miguel
 * 
 */
public class ServerCommDummy implements ServerComm {
	// static ServerSocket variable
	private static ServerSocket server;
	// socket server port on which it will listen
	private static int port = 9870;

	private boolean listening = true;
	protected LinkedList<Object> listOfOrders;
	private HashMap<String, MicroTraderCommServThread> mapOfClients = new HashMap<String, MicroTraderCommServThread>();

	@Override
	public void start() {
		try {
			listOfOrders = new LinkedList<Object>();
			ServerThread workingServer = new ServerThread(this);
			workingServer.start();
			System.out.println("Creating server socket...");
			server = new ServerSocket(port);
			while (listening) {
				System.out.println("Waiting for client request");
				// creating socket and waiting for client connection
				Socket socketl = server.accept();
				System.out.println("New Client");
				MicroTraderCommServThread listenerThread = new MicroTraderCommServThread(
						socketl);
				listenerThread.start();
			}
			server.close();
		} catch (IOException e) {

			e.printStackTrace();
		}

	}

	@Override
	public ServerSideMessage getNextMessage() {
		ServerMessage message = null;
		if (hasNextMessage()) {
			message = (ServerMessage) listOfOrders.get(0);
			listOfOrders.remove(0);
		}
		return message;
	}

	@Override
	public boolean hasNextMessage() {
		// TODO Auto-generated method stub
		return listOfOrders.size() > 0;
	}

	@Override
	public void sendOrder(String receiversNickname, Order order) {
		ClientMessage message = new ClientMessage(ClientSideMessage.Type.ORDER,
				order);
		MicroTraderCommServThread client = mapOfClients.get(receiversNickname);
		client.sendMessage(message);
	}

	@Override
	public void sendError(String toNickname, String error) {
		ClientMessage message = new ClientMessage(ClientSideMessage.Type.ERROR,
				error);
		MicroTraderCommServThread client = mapOfClients.get(toNickname);
		client.sendMessage(message);
	}

	@Override
	public boolean clientIsConnected(String nickname) {
		return mapOfClients.containsKey(nickname);
	}

	@Override
	public void disconnectClient(String nickname) {
		mapOfClients.remove(nickname);
	}

	private class ServerThread extends Thread {
		ServerCommDummy servercom;
		MicroTraderServerDummy workingServer;

		public ServerThread(ServerCommDummy _comm) {
			servercom = _comm;
		}

		@Override
		public void run() {
			System.out.println("Starting server...");
			workingServer = new MicroTraderServerDummy();
			workingServer.start(servercom);
		}

		public MicroTraderServerDummy getServer() {
			return this.workingServer;
		}
	}

	private class MicroTraderCommServThread extends Thread {

		ObjectInputStream ois;
		ObjectOutputStream oos;
		Socket socket;
		public LinkedList<ClientMessage> messagesToSend;

		public MicroTraderCommServThread(Socket socketl) {
			this.setName("Server_Reciever_Thread");
			socket = socketl;
			messagesToSend = new LinkedList<ClientMessage>();
		}

		@Override
		public void run() {
			try {
				ois = new ObjectInputStream(socket.getInputStream());
				oos = new ObjectOutputStream(socket.getOutputStream());
				while (true) {

					// read from socket to ObjectInputStream object

					// convert ObjectInputStream object to String
					ServerMessage message = (ServerMessage) ois.readObject();
					System.out.println("Connected: "
							+ message.getSenderNickname());
					listOfOrders.add(message);

					// System.out.println("message type Added - "+
					// message.getType());
					//
					// // if(messagesToSend.size() > 0){
					//
					// oos.writeObject(null);
					// }

					if (!mapOfClients.containsKey(message.getSenderNickname()))
						mapOfClients.put(message.getSenderNickname(), this);
				}
			} catch (Exception e) {

			}

		}

		public void sendMessage(ClientMessage obj) {
			try {
				// oos = new ObjectOutputStream(socket.getOutputStream());
				oos.writeObject(obj);
				oos.flush();
				// messagesToSend.add(obj);
			} catch (IOException e) {
				System.out.println("couldn't send message" + e.getMessage());
			}
		}
	}
}